import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.io.FileUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class AndroidAppGenerator {

	private static String templateProjectPath = "../AndroidTemplateApp";
	private static String projectBasePath = "c:\\temp\\";
	private static String appName = "TestApp";
	private static String appPath = projectBasePath + appName;
	private static String appPathSrc = appPath + "/src/com/example/template/";
	private static String appPathLayout = appPath + "/res/layout/";
	private static String appPathValues = appPath + "/res/values/";
	private static String appPathLayoutTemplate = appPathLayout + "activity_main_template.xml";
	private static String activityBaseName = "MainActivity";
	private static String receiverBaseName = "MainReceiver";
	private static String serviceBaseName = "MainService";
	private static String providerBaseName = "MainProvider";
	private static int maxDepth = 3;
	private static int numLeaf = 0; //used for non shared only
	private static boolean enableToasts = false;
	
	//for shared sub nodes/activities
	private static int numSubConnections = 3;
	private static int numActivityAdded = 0; //for shared path creation, multi path to target
	
	private static int numBroadcastReceiver = 0;
	private static int numBroadcastToSend = 0;
	private static int numBroadcastAdded = 0;
	
	private static int numService = 0;
	private static int numServiceToStart = 0;
	private static int numServiceStarted = 0;	
	
	private static int numProvider = 0;
	private static int numProviderToAccess = 0;
	private static int numProviderAccessed = 0;	
	
	//conditions based on input values to reach next activities
	private static boolean enableConditions = false;
	private static int lowConditionValue = 1;
	private static int highConditionValue = 99;	
	//these two must be kept in sync
	private static int numConditionsAdded = 0;
	private static int numConditionsAddedLayout = 0;
	
	//conditions based on sequence of events/button 
	private static boolean enableConditionsSequence = true;
	//use button click count as a condition to reach next activities - can get really difficult if combined with input conditions
	private static boolean useConditionsSequence = true;
	//how many times the sequence button must be clicked 
	private static int minSequenceCount = 1; 
	//reset sequence counter on clicking other stuff
	private static boolean resetConditionSequence = true;
	
	//conditions for each activity - not tied to buttons or launching new activities
	public static boolean enableConditionsComplex = false;
	private static int numConditionsToAddComplex = 3;
	
	private static boolean enableMethodDepthGen = false;
	private static int numMethodDepthToGen = 2;
	
	//mark/target/hotspot count
	private static int numTarget = 50000;
	private static int numTargetAdded = 0;
	
	XPathFactory xFactory = XPathFactory.newInstance();
	XPath xp = xFactory.newXPath();
	XPathExpression expr = null;
	
	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{
		if (args.length > 0)
			ParseInputFile(args[0]);
		
		AndroidAppGenerator gen = new AndroidAppGenerator();
		gen.GenerateApp();

	}
	
	public static void ParseInputFile(String path)
	{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try 
		{
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document dom = db.parse(path);
			Element root = dom.getDocumentElement();
			NodeList nl = root.getElementsByTagName("Parameter");
			if(nl != null && nl.getLength() > 0) 
			{
				for(int i = 0 ; i < nl.getLength();i++) 
				{
					Element el = (Element)nl.item(i);
					String name = el.getAttribute("name");
					String value = el.getAttribute("value");
					
					if ("templateProjectPath".equals(name))
						templateProjectPath = value;
					else if ("projectBasePath".equals(name))
						projectBasePath = value;
					else if ("appName".equals(name))
						appName = value;
					/*
					else if ("appPath".equals(name))
						appPath = value;
					else if ("appPathSrc".equals(name))
						appPathSrc = value;
					else if ("appPathLayout".equals(name))
						appPathLayout = value;
					else if ("appPathValues".equals(name))
						appPathValues = value;
					else if ("appPathLayoutTemplate".equals(name))
						appPathLayoutTemplate = value;
						*/
					else if ("activityBaseName".equals(name))
						activityBaseName = value;
					else if ("receiverBaseName".equals(name))
						receiverBaseName = value;
					else if ("serviceBaseName".equals(name))
						serviceBaseName = value;
					else if ("providerBaseName".equals(name))
						providerBaseName = value;
					else if ("maxDepth".equals(name))
						maxDepth = Integer.parseInt(value);
					else if ("numLeaf".equals(name))
						numLeaf = Integer.parseInt(value);
					else if ("enableToasts".equals(name))
						enableToasts = Boolean.parseBoolean(value);
					else if ("providerBaseName".equals(name))
						providerBaseName = value;
					else if ("providerBaseName".equals(name))
						providerBaseName = value;
					else if ("numSubConnections".equals(name))
						numSubConnections = Integer.parseInt(value);
					//else if ("numActivityAdded".equals(name))
						//numActivityAdded = Integer.parseInt(value);
					else if ("numBroadcastReceiver".equals(name))
						numBroadcastReceiver = Integer.parseInt(value);
					else if ("numBroadcastToSend".equals(name))
						numBroadcastToSend = Integer.parseInt(value);
					//else if ("numBroadcastAdded".equals(name))
						//numBroadcastAdded = Integer.parseInt(value);
					else if ("numService".equals(name))
						numService = Integer.parseInt(value);
					else if ("numServiceToStart".equals(name))
						numServiceToStart = Integer.parseInt(value);
					//else if ("numServiceStarted".equals(name))
						//numServiceStarted = Integer.parseInt(value);				
					else if ("numProvider".equals(name))
						numProvider = Integer.parseInt(value);
					else if ("numProviderToAccess".equals(name))
						numProviderToAccess = Integer.parseInt(value);
					//else if ("numProviderAccessed".equals(name))
						//numProviderAccessed = Integer.parseInt(value);
					else if ("enableConditions".equals(name))
						enableConditions = Boolean.parseBoolean(value);
					else if ("lowConditionValue".equals(name))
						lowConditionValue = Integer.parseInt(value);
					else if ("highConditionValue".equals(name))
						highConditionValue = Integer.parseInt(value);
					//else if ("numConditionsAdded".equals(name))
						//numConditionsAdded = Integer.parseInt(value);
					//else if ("numConditionsAddedLayout".equals(name))
						//numConditionsAddedLayout = Integer.parseInt(value);
					else if ("enableConditionsSequence".equals(name))
						enableConditionsSequence = Boolean.parseBoolean(value);
					else if ("useConditionsSequence".equals(name))
						useConditionsSequence = Boolean.parseBoolean(value);					
					else if ("minSequenceCount".equals(name))
						minSequenceCount = Integer.parseInt(value);			
					else if ("resetConditionSequence".equals(name))
						resetConditionSequence = Boolean.parseBoolean(value);
					else if ("enableConditionsComplex".equals(name))
						enableConditionsComplex = Boolean.parseBoolean(value);				
					else if ("numConditionsToAddComplex".equals(name))
						numConditionsToAddComplex = Integer.parseInt(value);					
					else if ("enableMethodDepthGen".equals(name))
						enableMethodDepthGen = Boolean.parseBoolean(value);
					else if ("numMethodDepthToGen".equals(name))
						numMethodDepthToGen = Integer.parseInt(value);	
					else if ("numTarget".equals(name))
						numTarget = Integer.parseInt(value);			
					
					appPath = projectBasePath + appName;
					appPathSrc = appPath + "/src/com/example/template/";
					appPathLayout = appPath + "/res/layout/";
					appPathValues = appPath + "/res/values/";
					appPathLayoutTemplate = appPathLayout + "activity_main_template.xml";
					
				}
			}	
		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch(SAXException se) {
			se.printStackTrace();
		}catch(IOException ioe) {
			ioe.printStackTrace();
		}
				
	}
	
	public void GenerateApp()
	{
		try
		{
			FileUtils.deleteDirectory(new File(appPath));
			new File(appPath).mkdirs();  
			FileUtils.copyDirectory(new File(templateProjectPath), new File(appPath));
			
			/*
			this.CreateActivity("MainActivity", numLeaf, 1);
			this.CreateBroadcastReceivers(receiverBaseName, numBroadcastReceiver);
			this.CreateServices(serviceBaseName, numService);
			this.CreateProviders(providerBaseName, numProvider);
			*/
			GenerateAppShared();
		}catch(Exception ex){
			ex.printStackTrace();
		}
		
		
	}

	private void CreateActivity(String activityName, int numSubActivity, int currentDepth)
	{

		if (currentDepth > maxDepth)
			return;
		else if (currentDepth == maxDepth)
			numSubActivity = 0;
		
		writeActivityFile(activityName, numSubActivity);
		writeLayoutFile(activityName, numSubActivity);
		writeManifestFile(activityName, numSubActivity);
		writeStringsFile(activityName, numSubActivity);
		
		for (int i = 0; i < numSubActivity;i++)
		{
			String subActivityName = activityName+i+"SubActivity";
			this.CreateActivity(subActivityName,numLeaf, currentDepth+1);
		}
	}
	
	private void writeActivityFile(String activityName, int numSubActivity)
	{
		//delete the default main activity and create a new one
		String activityFile = appPathSrc + activityName+".java";
		File ma = new File(activityFile);
		if (ma.exists())
			ma.delete();
		String activityContent = mActivityClassTextTop.replaceAll("_ACTIVITY_NAME_", activityName);
		for (int i = 0; i < numSubActivity; i ++)
		{
			activityContent += "private Button " + activityName+"aButton"+i+";\n";
		}
		if (enableConditionsComplex){
			activityContent += "private Button " + activityName+"aButtonComplex;\n";
		}		
		if (enableConditionsSequence && numSubActivity > 0){
			activityContent += "private int " + "myButtonClickCounter = 0;\n";
			activityContent += "private Button " + activityName+"aButtonSequence;\n";
		}
		
		activityContent += "\n" + mActivityClassTextOnCreateTop.replaceAll("_LAYOUT_NAME_", "R.layout." + activityName.toLowerCase());
		for (int i = 0; i < numSubActivity; i ++)
		{
			String buttonName = activityName+"aButton" + i;
			activityContent += buttonName+" = (Button)this.findViewById(R.id."+buttonName+"Id);\n";
			activityContent += buttonName+"Handler "+activityName+"aButtonListener"+i+" = new "+buttonName+"Handler();\n";
			activityContent += buttonName+".setOnClickListener("+activityName+"aButtonListener"+i+");\n";
		}			
		if (enableConditionsComplex){
			String buttonName = activityName+"aButtonComplex";
			activityContent += buttonName+" = (Button)this.findViewById(R.id."+buttonName+"Id);\n";
			activityContent += buttonName+"Handler "+activityName+"aButtonListenerComplex = new "+buttonName+"Handler();\n";
			activityContent += buttonName+".setOnClickListener("+activityName+"aButtonListenerComplex);\n";			
		}
		if (enableConditionsSequence && numSubActivity > 0){
			String buttonName = activityName+"aButtonSequence";
			activityContent += buttonName+" = (Button)this.findViewById(R.id."+buttonName+"Id);\n";
			activityContent += buttonName+"Handler "+activityName+"aButtonListenerSequence = new "+buttonName+"Handler();\n";
			activityContent += buttonName+".setOnClickListener("+activityName+"aButtonListenerSequence);\n";			
		}
		
		////////////////////////////////////////////////////////////////////////////////////
		//for leaf node/activities only
		if (numSubActivity <= 0)
		{
			//broadcast some intents to the broadcast receivers
			if (numBroadcastToSend > 0)
			{
				numBroadcastToSend--;
				String actionName = receiverBaseName + numBroadcastAdded + "ReceiverAction";
				String broadcastText = "Intent intent = new Intent(\"" + actionName + "\");\n";
				broadcastText += "sendBroadcast(intent);\n";		
				activityContent += broadcastText + "\n";
				numBroadcastAdded++;
			}		
			
			//start some services
			else if (numServiceToStart > 0)
			{
				numServiceToStart--;
				String aServiceName = serviceBaseName + numServiceStarted + "Service";
				String serviceText = "Intent intent = new Intent(this,"+aServiceName+".class);\n";
				serviceText += "startService(intent);\n";		
				activityContent += serviceText + "\n";
				numServiceStarted++;
			}
			
			//access some content providers
			else if (numProviderToAccess > 0)
			{
				numProviderToAccess--;
				String aProviderName = providerBaseName + numProviderAccessed + "Provider";
				String providerText = "super.managedQuery("+aProviderName+".CONTENT_URI, null, null, null, null);\n"; //deprecated method, but ok for our purpose	
				activityContent += providerText + "\n";
				numProviderAccessed++;
			}			
		}
		////////////////////////////////////////////////////////////////////////////////////
		
		activityContent = potentiallyAddTarget(activityContent,true);
		activityContent +=  mActivityClassTextOnCreateBottom;
		
		for (int i = 0; i < numSubActivity; i ++)
		{			
			String buttonName = activityName+"aButton" + i;
			String listernerText = mActivityClassTextListenerTop.replaceAll("_BUTTON_CLICK_LISTENER_NAME_", buttonName+"Handler");
			
			
			String subActivityName = activityName+i+"SubActivity";
			String onClickBodyText = "Intent myIntent = new Intent("+activityName+".this, "+subActivityName+".class);\n";
			
			//for the conditions
			//first one has 0, then 1 and 2 (nested) and so on	
			if (enableConditions)
			{
				Random r = new Random();
				for (int j = 0; j< i; j++)
				{
					int randomValue = r.nextInt(highConditionValue)+lowConditionValue;
					String inputName = activityName+"anInput"+numConditionsAdded+"Id";
					onClickBodyText += "EditText "+inputName+" = (EditText)findViewById(R.id." + inputName+");\n";
					
					String inputNameDouble = inputName+"Double";
					onClickBodyText += "double "+inputNameDouble+" = 0.0;\n";
					onClickBodyText += "if (" + inputName + " != null && !"+inputName+".getText().toString().equals(\"\")) {\n";				
						onClickBodyText += inputNameDouble+" = Double.parseDouble("+inputName+".getText().toString());\n";
						onClickBodyText += "}\n if (" + inputNameDouble + " > "+randomValue+"){\n";
					numConditionsAdded++;
				}
			}
			
				//condition for sequence counter to be used as well
				if (enableConditionsSequence && useConditionsSequence) 
					onClickBodyText += "if (myButtonClickCounter >=" + minSequenceCount + "){\n";
				
					onClickBodyText += activityName+".this.startActivity(myIntent);\n";	
					onClickBodyText = potentiallyAddTarget(onClickBodyText,true);
					
				if (enableConditionsSequence && useConditionsSequence){
					onClickBodyText += "}\n";
					if (resetConditionSequence){
						onClickBodyText += "myButtonClickCounter=0;\n";
					}
				}
				
			if (enableConditions)
			for (int j = 0; j< i; j++)
				onClickBodyText += "}\n";
			
			
			listernerText = listernerText.replaceAll("_ON_CLICK_BODY_", onClickBodyText);
			
			activityContent +=  listernerText + "\n";
		}
		
		if (enableConditionsComplex)
		{			
			String buttonName = activityName+"aButtonComplex";
			String listernerText = mActivityClassTextListenerTop.replaceAll("_BUTTON_CLICK_LISTENER_NAME_", buttonName+"Handler");
			String onClickBodyText = "\n";
			
			Random r = new Random();
			for (int k = 0; k< numConditionsToAddComplex; k++)
			{
				int randomValue = r.nextInt(highConditionValue)+lowConditionValue;
				String inputName = activityName+"anInputComplex"+k+"Id";
				onClickBodyText += "EditText "+inputName+" = (EditText)findViewById(R.id." + inputName+");\n";
				
				String inputNameDouble = inputName+"Double";
				onClickBodyText += "double "+inputNameDouble+" = 0.0;\n";
				onClickBodyText += "if (" + inputName + " != null && !"+inputName+".getText().toString().equals(\"\")) {\n";				
					onClickBodyText += inputNameDouble+" = Double.parseDouble("+inputName+".getText().toString());\n";
					onClickBodyText += "}\n if (" + inputNameDouble + " > "+randomValue+"){\n";
			}

			onClickBodyText += "target();\n";	

			for (int k = 0; k< numConditionsToAddComplex; k++)
				onClickBodyText += "}\n";
			
			
			listernerText = listernerText.replaceAll("_ON_CLICK_BODY_", onClickBodyText);
			
			activityContent +=  listernerText + "\n";
		}	
		
		if (enableConditionsSequence && numSubActivity > 0)
		{			
			String buttonName = activityName+"aButtonSequence";
			String listernerText = mActivityClassTextListenerTop.replaceAll("_BUTTON_CLICK_LISTENER_NAME_", buttonName+"Handler");
			String onClickBodyText = "\n";
			
			onClickBodyText += "if (myButtonClickCounter >=" + minSequenceCount + "){\n";
				onClickBodyText += "target();\n";	
			onClickBodyText += "} else {\n";
				onClickBodyText += "myButtonClickCounter++;\n";
				onClickBodyText += "}\n";
						
			listernerText = listernerText.replaceAll("_ON_CLICK_BODY_", onClickBodyText);
			
			activityContent +=  listernerText + "\n";
		}
		
		
		activityContent +=  mActivityClassTextBottom;
		activityContent = activityContent.replaceAll("_TARGET_TEXT_", ""); //if a target wasn't assigned, remove the template text
		writeFile(activityFile, activityContent);			
	}
	
	private void writeLayoutFile(String activityName, int numSubActivity)
	{
		DocumentBuilderFactory dbf = null;
		DocumentBuilder db = null;
		Document dom = null;
		Element root = null;
		boolean writeOutput = false;
		
		try
		{
			//update the layout file and add the buttons
			dbf = DocumentBuilderFactory.newInstance();
			String layoutFile = appPathLayout + activityName+".xml";
			File layoutFileXml = new File(layoutFile.toLowerCase());
			if (!layoutFileXml.exists())
				FileUtils.copyFile(new File(appPathLayoutTemplate), layoutFileXml);
			
			if (numSubActivity > 0)
			{
				db = dbf.newDocumentBuilder();
				dom = db.parse(layoutFile);
				Element scroll = (Element)dom.getDocumentElement().getElementsByTagName("ScrollView").item(0);
				root = (Element)scroll.getElementsByTagName("LinearLayout").item(0);		
				for (int i = 0; i < numSubActivity; i ++)
				{
					//for the conditions
					//first one has 0, then 1 and 2 (nested) and so on
					if (enableConditions)
					{
						for (int j = 0; j < i; j++)
						{
							Element anInput = dom.createElement("EditText");
							anInput.setAttribute("android:id", "@+id/"+activityName+"anInput"+numConditionsAddedLayout+"Id");
							anInput.setAttribute("android:inputType", "numberDecimal");					
							anInput.setAttribute("android:layout_width", "wrap_content");
							anInput.setAttribute("android:layout_height", "wrap_content");
							root.appendChild(anInput);
							numConditionsAddedLayout++;
						}
					}
					
					Element aButton = dom.createElement("Button");
					aButton.setAttribute("android:id", "@+id/"+activityName+"aButton"+i+"Id");
					aButton.setAttribute("android:text", "@string/"+activityName+"aButton"+i+"Label");					
					aButton.setAttribute("android:layout_width", "wrap_content");
					aButton.setAttribute("android:layout_height", "wrap_content");
					root.appendChild(aButton);
					
				}
				writeOutput = true;
			}
			
			
			if (numConditionsToAddComplex > 0 && enableConditionsComplex)
			{
				if (db == null)
				{
					db = dbf.newDocumentBuilder();
					dom = db.parse(layoutFile);
					Element scroll = (Element)dom.getDocumentElement().getElementsByTagName("ScrollView").item(0);
					root = (Element)scroll.getElementsByTagName("LinearLayout").item(0);
				}
				for (int i = 0; i < numConditionsToAddComplex; i ++)
				{

					Element anInput = dom.createElement("EditText");
					anInput.setAttribute("android:id", "@+id/"+activityName+"anInputComplex"+i+"Id");
					anInput.setAttribute("android:inputType", "numberDecimal");					
					anInput.setAttribute("android:layout_width", "wrap_content");
					anInput.setAttribute("android:layout_height", "wrap_content");
					root.appendChild(anInput);
				}
				
				//only one of these per activity that launches the handler for the conditions above
				Element aButton = dom.createElement("Button");
				aButton.setAttribute("android:id", "@+id/"+activityName+"aButtonComplexId");
				aButton.setAttribute("android:text", "@string/"+activityName+"aButtonComplexLabel");					
				aButton.setAttribute("android:layout_width", "wrap_content");
				aButton.setAttribute("android:layout_height", "wrap_content");
				root.appendChild(aButton);		
				
				writeOutput = true;
			}
			
			if (minSequenceCount > 0 && enableConditionsSequence)
			{
				if (db == null)
				{
					db = dbf.newDocumentBuilder();
					dom = db.parse(layoutFile);
					Element scroll = (Element)dom.getDocumentElement().getElementsByTagName("ScrollView").item(0);
					root = (Element)scroll.getElementsByTagName("LinearLayout").item(0);
				}
				
				//only one of these per activity that launches the handler for the conditions above
				Element aButton = dom.createElement("Button");
				aButton.setAttribute("android:id", "@+id/"+activityName+"aButtonSequenceId");
				aButton.setAttribute("android:text", "@string/"+activityName+"aButtonSequenceLabel");					
				aButton.setAttribute("android:layout_width", "wrap_content");
				aButton.setAttribute("android:layout_height", "wrap_content");
				root.appendChild(aButton);		
				
				writeOutput = true;
			}
			
			if (writeOutput)
				writeXmlFile(dom, layoutFile);
			
		}catch(Exception e)
		{
			e.printStackTrace();
		}		
	}
	
	private void writeManifestFile(String activityName, int numSubActivity)
	{
		////////////////
		DocumentBuilderFactory dbf = null;
		DocumentBuilder db = null;
		Document dom = null;
		Element root = null;

			try
			{
				//deep clone the main activity to set up additional activities
				 dbf = DocumentBuilderFactory.newInstance();
				String manifestFile = appPath + "/AndroidManifest.xml";
				 db = dbf.newDocumentBuilder();
				 dom = db.parse(manifestFile);
				 root = dom.getDocumentElement();
				NodeList applicationList = root.getElementsByTagName("application");
				Element appElement = (Element) applicationList.item(0);
				
				//change name of the main activity
				NodeList nl = root.getElementsByTagName("activity");
				Element mainActivityElement = (Element) nl.item(0);
				//mainActivityElement.setAttribute("android:name", "."+appName+"Activity");
				
				for (int i = 0; i < numSubActivity; i ++)
				{
					Element copy = (Element)mainActivityElement.cloneNode(true);
					
					//change activity label and name
					String subActivityName = activityName+i+"SubActivity";
					copy.setAttribute("android:label", "@string/"+subActivityName);
					copy.setAttribute("android:name", "."+subActivityName);
					
					//change the action type
					NodeList actionList = copy.getElementsByTagName("action");
					Element action = (Element) actionList.item(0);
					action.setAttribute("android:name", "android.intent.action.SEND");
					
					//change the category
					NodeList categoryList = copy.getElementsByTagName("category");
					Element category = (Element) categoryList.item(0);
					category.setAttribute("android:name", "android.intent.category.DEFAULT");
					
					appElement.appendChild(copy);
				}				
				
				writeXmlFile(dom, manifestFile);
			}catch(Exception e){
				e.printStackTrace();
			}		
	}
	
	private void writeStringsFile(String activityName, int numSubActivity)
	{
		DocumentBuilderFactory dbf = null;
		DocumentBuilder db = null;
		Document dom = null;
		Element root = null;
		
		try
		{				
			//update the string values file
			dbf = DocumentBuilderFactory.newInstance();
			String valuesFile = appPathValues + "strings.xml";
			db = dbf.newDocumentBuilder();
			dom = db.parse(valuesFile);
			root = dom.getDocumentElement();		
			for (int i = 0; i < numSubActivity; i ++)
			{
				String subActivityName = activityName+i+"SubActivity";
				//for the activities
				Element aValue = dom.createElement("string");
				aValue.setAttribute("name", subActivityName);
				aValue.setTextContent(subActivityName);
				root.appendChild(aValue);				
				
				
				//for the buttons
				String buttonLabel = activityName+"aButton"+i+"Label";
				aValue = dom.createElement("string");
				aValue.setAttribute("name", buttonLabel);
				aValue.setTextContent(buttonLabel);
				
				String xpath = "//*[@name='"+buttonLabel+"']";
				expr = xp.compile(xpath);
				Object result = expr.evaluate(dom, XPathConstants.NODESET);
				NodeList nl2 = (NodeList) result;
				if(nl2 == null || nl2.getLength() <= 0) 
					root.appendChild(aValue);
			}

			if (enableConditionsComplex)
			{
				//for the buttons
				String buttonLabel = activityName+"aButtonComplexLabel";
				Element aValue = dom.createElement("string");
				aValue.setAttribute("name", buttonLabel);
				aValue.setTextContent(buttonLabel);
				
				String xpath = "//*[@name='"+buttonLabel+"']";
				expr = xp.compile(xpath);
				Object result = expr.evaluate(dom, XPathConstants.NODESET);
				NodeList nl2 = (NodeList) result;
				if(nl2 == null || nl2.getLength() <= 0) 
					root.appendChild(aValue);				
			}
			
			if (enableConditionsSequence)
			{
				//for the buttons
				String buttonLabel = activityName+"aButtonSequenceLabel";
				Element aValue = dom.createElement("string");
				aValue.setAttribute("name", buttonLabel);
				aValue.setTextContent(buttonLabel);
				
				String xpath = "//*[@name='"+buttonLabel+"']";
				expr = xp.compile(xpath);
				Object result = expr.evaluate(dom, XPathConstants.NODESET);
				NodeList nl2 = (NodeList) result;
				if(nl2 == null || nl2.getLength() <= 0) 
					root.appendChild(aValue);				
			}
			
			writeXmlFile(dom, valuesFile);	
		}catch(Exception ex)
		{
			ex.printStackTrace();
		}		
	}
	
	
	private void CreateBroadcastReceivers(String receiverName, int numReceiver)
	{
		DocumentBuilderFactory dbf = null;
		DocumentBuilder db = null;
		Document dom = null;
		Element root = null;
		
		try
		{				
			 dbf = DocumentBuilderFactory.newInstance();
			 String manifestFile = appPath + "/AndroidManifest.xml";
			 db = dbf.newDocumentBuilder();
			 dom = db.parse(manifestFile);
			 root = dom.getDocumentElement();
			NodeList applicationList = root.getElementsByTagName("application");
			Element appElement = (Element) applicationList.item(0);
				
			//broadcast receivers
			for (int i = 0; i < numReceiver; i ++)
			{
				String aReceiverName = receiverName + i + "Receiver";
				Element aReceiver = dom.createElement("receiver");
				aReceiver.setAttribute("android:name", aReceiverName);
				Element aReceiverIntentFilter = dom.createElement("intent-filter");
				Element aReceiverAction = dom.createElement("action");
				aReceiverAction.setAttribute("android:name", aReceiverName+"Action");
				aReceiverIntentFilter.appendChild(aReceiverAction);
				aReceiver.appendChild(aReceiverIntentFilter);
				appElement.appendChild(aReceiver);	
				
				//create the java files
				String receiverFile = appPathSrc + aReceiverName+".java";
				File rf = new File(receiverFile);
				if (rf.exists())
					rf.delete();
				String receiverContent = mReceiverClassText.replaceAll("_RECEIVER_NAME_", aReceiverName);
				String rBody = "\n";
				if (enableToasts)
					rBody = "Toast.makeText(context, \"broadcast\", Toast.LENGTH_LONG).show();\n";
				
				rBody = potentiallyAddTarget(rBody,true);
				receiverContent = receiverContent.replaceAll("_ON_RECEIVE_BODY_", rBody);
				
				receiverContent = potentiallyAddTarget(receiverContent,false);
				receiverContent = receiverContent.replaceAll("_TARGET_TEXT_", ""); //if a target wasn't assigned, remove the template text
				this.writeFile(receiverFile, receiverContent);
			}
			writeXmlFile(dom, manifestFile);
				
		}catch(Exception ex)
		{
			ex.printStackTrace();
		}		
	}	
	
	private void CreateServices(String serviceName, int numServices)
	{
		DocumentBuilderFactory dbf = null;
		DocumentBuilder db = null;
		Document dom = null;
		Element root = null;
		
		try
		{				
			 dbf = DocumentBuilderFactory.newInstance();
			 String manifestFile = appPath + "/AndroidManifest.xml";
			 db = dbf.newDocumentBuilder();
			 dom = db.parse(manifestFile);
			 root = dom.getDocumentElement();
			NodeList applicationList = root.getElementsByTagName("application");
			Element appElement = (Element) applicationList.item(0);
				
			//services
			for (int i = 0; i < numServices; i ++)
			{
				String aServiceName = serviceName + i + "Service";
				Element aService= dom.createElement("service");
				aService.setAttribute("android:name", aServiceName);
				appElement.appendChild(aService);	
				
				//create the java files
				String serviceFile = appPathSrc + aServiceName+".java";
				File rf = new File(serviceFile);
				if (rf.exists())
					rf.delete();
				String serviceContent = mServiceClassText.replaceAll("_SERVICE_NAME_", aServiceName);
				String sBody = "\n";
				if (enableToasts)
					sBody = "Toast.makeText(getApplicationContext(), \"service-startCommand\", Toast.LENGTH_LONG).show();\n";
				
				sBody = potentiallyAddTarget(sBody,true);
				serviceContent = serviceContent.replaceAll("_ON_START_COMMAND_BODY_", sBody);							
				serviceContent = potentiallyAddTarget(serviceContent,false);
				
				sBody = "\n";
				if (enableToasts)
					sBody = "Toast.makeText(getApplicationContext(), \"service-bind\", Toast.LENGTH_LONG).show();\n";

				serviceContent = serviceContent.replaceAll("_ON_BIND_BODY_", sBody);		
				
				serviceContent = serviceContent.replaceAll("_TARGET_TEXT_", ""); //if a target wasn't assigned, remove the template text
				this.writeFile(serviceFile, serviceContent);
			}
			writeXmlFile(dom, manifestFile);
				
		}catch(Exception ex)
		{
			ex.printStackTrace();
		}		
	}
	
	
	private void CreateProviders(String providerName, int numProviders)
	{
		DocumentBuilderFactory dbf = null;
		DocumentBuilder db = null;
		Document dom = null;
		Element root = null;
		
		try
		{				
			 dbf = DocumentBuilderFactory.newInstance();
			 String manifestFile = appPath + "/AndroidManifest.xml";
			 db = dbf.newDocumentBuilder();
			 dom = db.parse(manifestFile);
			 root = dom.getDocumentElement();
			NodeList applicationList = root.getElementsByTagName("application");
			Element appElement = (Element) applicationList.item(0);
				
			//content providers
			for (int i = 0; i < numProviders; i ++)
			{
				String aProviderName = providerName + i + "Provider";
				String aProviderAuthority = providerName + i + "Authority";
				Element aProvider= dom.createElement("provider");
				aProvider.setAttribute("android:name", aProviderName);
				aProvider.setAttribute("android:authorities", aProviderAuthority);
				aProvider.setAttribute("android:exported", "false");
				appElement.appendChild(aProvider);	
				
				//create the java files
				String providerFile = appPathSrc + aProviderName+".java";
				File rf = new File(providerFile);
				if (rf.exists())
					rf.delete();
				String providerContent = mProviderClassText.replaceAll("_PROVIDER_NAME_", aProviderName);
				providerContent = providerContent.replaceAll("_AUTHORITY_NAME_", aProviderAuthority);
				
				String pBody = "return false;\n";
				if (enableToasts)
					pBody = "Toast.makeText(getContext(), \"provider-onCreate\", Toast.LENGTH_LONG).show();\nreturn false;\n";
				providerContent = providerContent.replaceAll("_ON_CREATE_BODY_", pBody);
				
				pBody = "";
				pBody = potentiallyAddTarget(pBody,true);
				if (enableToasts)
					pBody += "Toast.makeText(getContext(), \"provider-query\", Toast.LENGTH_LONG).show();\nreturn null;\n";
				else
					pBody += "return null;\n";
				
				providerContent = potentiallyAddTarget(providerContent,false);
				
				providerContent = providerContent.replaceAll("_QUERY_BODY_", pBody);
				pBody = "return null;\n";
				if (enableToasts)				
					pBody = "Toast.makeText(getContext(), \"provider-insert\", Toast.LENGTH_LONG).show();\nreturn null;\n";
				providerContent = providerContent.replaceAll("_INSERT_BODY_", pBody);
				pBody = "return 0;\n";
				if (enableToasts)
					pBody = "Toast.makeText(getContext(), \"provider-delete\", Toast.LENGTH_LONG).show();\nreturn 0;\n";
				providerContent = providerContent.replaceAll("_DELETE_BODY_", pBody);
				pBody = "return 0;\n";
				if (enableToasts)
					pBody = "Toast.makeText(getContext(), \"provider-update\", Toast.LENGTH_LONG).show();\nreturn 0;\n";
				providerContent = providerContent.replaceAll("_UPDATE_BODY_", pBody);	
				
				providerContent = providerContent.replaceAll("_TARGET_TEXT_", ""); //if a target wasn't assigned, remove the template text
				this.writeFile(providerFile, providerContent);
			}
			writeXmlFile(dom, manifestFile);
				
		}catch(Exception ex)
		{
			ex.printStackTrace();
		}		
	}
	
	public static void writeXmlFile(Document doc, String filename) {
	    try {
	        // Prepare the DOM document for writing
	        Source source = new DOMSource(doc);

	        // Prepare the output file
	        File file = new File(filename);
	        Result result = new StreamResult(file);

	        // Write the DOM document to the file
	        Transformer xformer = TransformerFactory.newInstance().newTransformer();
	        xformer.transform(source, result);
	    } catch (TransformerConfigurationException e) {
	    } catch (TransformerException e) {
	    }
	}	
	
	private void writeFile(String path, String text)
	{
		try
		{
		  FileWriter fstream = new FileWriter(path,true);
		  BufferedWriter out = new BufferedWriter(fstream);
		  out.write(text);
		  out.close();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		  	
	}
	
	private String potentiallyAddTarget(String sourceString, boolean addCall)
	{
		Random r = new Random();
		if (numTargetAdded <= numTarget)// && r.nextFloat() > .5)
		{
			sourceString = sourceString.replaceAll("_TARGET_TEXT_", "private void target(){};\n"); 
			if (addCall) sourceString += "target();\n";
			numTargetAdded++;
		}
		return sourceString;
	}
	
	private static String mActivityClassTextTop = "package com.example.template;\n\n"+
						"import android.app.Activity;\n"+
						"import android.content.Context;\n"+
						"import android.os.Bundle;\n"+
						"import android.telephony.TelephonyManager;\n"+
						"import android.util.Log;\n"+
						"import android.view.View;\n"+
						"import android.view.View.OnClickListener;\n"+
						"import android.widget.Button;\n"+
						"import android.widget.EditText;\n"+
						"import android.content.Intent;\n"+
						"import android.widget.TextView;\n\n"+

						"public class _ACTIVITY_NAME_ extends Activity \n"+
						"{\n"+
							"_TARGET_TEXT_ \n"+
							"_METHOD_DEPTH_TEXT_ \n";
							//private Button addButton;
							
	private static String mActivityClassTextOnCreateTop = "@Override\n"+
						    "public void onCreate(Bundle savedInstanceState)\n"+
						    "{\n"+
						        "super.onCreate(savedInstanceState);\n"+
						        "setContentView(_LAYOUT_NAME_);\n";
						        
						        //addButton = (Button)this.findViewById(R.id.btnAddId);
						        //Adder addListener = new Adder();
						        //addButton.setOnClickListener(addListener);

	private static String mActivityClassTextOnCreateBottom = "}\n";
						    
	private static String mActivityClassTextListenerTop =	"public class _BUTTON_CLICK_LISTENER_NAME_ implements OnClickListener\n"+
						    "{\n"+
						    	"public void onClick(View v) \n"+
						    	"{\n"+
						    		"_ON_CLICK_BODY_" + 
						    		//Intent myIntent = new Intent(CurrentActivity.this, NextActivity.class);
						    		//CurrentActivity.this.startActivity(myIntent);
						    	"}\n"+
						    "}\n";
	private static String mActivityClassTextBottom = "_TARGET_TEXT_ \n}";
	
	private static String mReceiverClassText = "package com.example.template;\n\n"+
			"import android.content.BroadcastReceiver;\n"+
			"import android.widget.Toast;\n"+
			"import android.content.Context;\n"+
			"import android.content.Intent;\n\n"+

			"public class _RECEIVER_NAME_ extends BroadcastReceiver {\n"+
				"_TARGET_TEXT_ \n"+
				"@Override\n"+
				"public void onReceive(Context context, Intent intent) {\n"+
					"_ON_RECEIVE_BODY_ \n"+
				"}\n\n"+
			"}\n";
	
	private static String mServiceClassText = "package com.example.template;\n\n"+
			"import android.widget.Toast;\n"+
			"import android.content.Context;\n"+
			"import android.app.Service;\n"+
			"import android.os.Binder;\n"+
			"import android.os.IBinder;\n"+			
			"import android.content.Intent;\n\n"+			

			"public class _SERVICE_NAME_ extends Service {\n\n"+
				"_TARGET_TEXT_ \n"+
			
			  "@Override\n"+
			  "public int onStartCommand(Intent intent, int flags, int startId) {\n"+
				"_ON_START_COMMAND_BODY_ \n"+
			    "return Service.START_NOT_STICKY;\n"+
			  "}\n\n"+
			
			  "@Override\n"+
			  "public IBinder onBind(Intent intent) {\n"+
				"_ON_BIND_BODY_ \n"+
			    "return null;\n"+
			  "}\n\n"+
					
			"}\n";	
	
	private static String mProviderClassText = "package com.example.template;\n\n"+
			"import android.content.ContentProvider;\n"+
			"import android.content.ContentResolver;\n"+
			"import android.content.ContentValues;\n"+
			"import android.content.UriMatcher;\n"+
			"import android.database.Cursor;\n"+
			"import android.database.sqlite.SQLiteDatabase;\n"+
			"import android.database.sqlite.SQLiteQueryBuilder;\n"+
			"import android.net.Uri;\n"+
			"import android.widget.Toast;\n"+
			"import android.text.TextUtils;\n\n"+
		
			"public class _PROVIDER_NAME_ extends ContentProvider {\n\n"+
				"_TARGET_TEXT_ \n"+
			
				"private static final String AUTHORITY = \"_AUTHORITY_NAME_\";\n"+
				"public static final Uri CONTENT_URI = Uri.parse(\"content://\" + AUTHORITY + \"/dummy\");\n"+
	
			  "@Override\n"+
			  "public boolean onCreate() {\n"+
			  	"_ON_CREATE_BODY_ \n"+
			  "}\n"+
		
			  "@Override\n"+
			  "public Cursor query(Uri uri, String[] projection, String selection,\n"+
			      "String[] selectionArgs, String sortOrder) {\n"+				  
				"_QUERY_BODY_ \n"+
			  "}\n"+
		
			  "@Override\n"+
			  "public String getType(Uri uri) {\n"+
			    "return null;\n"+
			  "}\n"+
		
			  "@Override\n"+
			  "public Uri insert(Uri uri, ContentValues values) {\n"+
			  	"_INSERT_BODY_ \n"+
			  "}\n"+
		
			  "@Override\n"+
			  "public int delete(Uri uri, String selection, String[] selectionArgs) {\n"+
			  	"_DELETE_BODY_ \n"+
			  "}\n"+
		
			  "@Override\n"+
			  "public int update(Uri uri, ContentValues values, String selection,\n"+
			      "String[] selectionArgs) {\n"+
			      "_UPDATE_BODY_ \n"+
			  "}\n\n"+
			"}\n";
	
	/////////////////////////////////////////////////////////////////////////
	
	public void GenerateAppShared()
	{
		try
		{
			int prevLevelActivityCount = 0;
			int numSub = numSubConnections;
			int nextLevelStartingNumber = 0;
			int nextLevelConnectionNumber = 0;
			
			for (int i = 0; i < maxDepth; i++)
			{
				int numActivity = prevLevelActivityCount + (int)Math.pow((numSubConnections - 1),i);
				if (numActivityAdded == 0)
					nextLevelStartingNumber = 2;
				else
					nextLevelStartingNumber = numActivityAdded+numActivity+1;
				
				for (int j = 1; j <= numActivity; j++)
				{
					nextLevelConnectionNumber = nextLevelStartingNumber + ((numSub-1) * (j-1));
					numActivityAdded++;
					if (i== (maxDepth-1)) numSub = 0;
					String activityName = activityBaseName;
					if (i > 0) activityName += numActivityAdded;
									
					writeActivityFileShared(activityName, numSub, nextLevelConnectionNumber);	
					writeLayoutFile(activityName, numSub);
					if (i > 0) writeManifestFileShared(activityName, numSub);
					writeStringsFileShared(activityName, numSub);
					
					numConditionsAdded = 0;
					numConditionsAddedLayout = 0;
				}
				prevLevelActivityCount = numActivity;
			}
						
		}catch(Exception ex)
		{
			ex.printStackTrace();
		}

	}
	
	private void writeActivityFileShared(String activityName, int numSubActivity, int nextLevelConnectionNumber)
	{
		String activityFile = appPathSrc + activityName+".java";
		File af = new File(activityFile);
		if (af.exists())
			af.delete();
		String activityContent = mActivityClassTextTop.replaceAll("_ACTIVITY_NAME_", activityName);
		
		for (int i = 0; i < numSubActivity; i ++)
		{
			activityContent += "private Button " + activityName+"aButton"+i+";\n";
		}
		if (enableConditionsComplex){
			activityContent += "private Button " + activityName+"aButtonComplex;\n";
		}
		if (enableConditionsSequence && numSubActivity > 0){
			activityContent += "private int " + "myButtonClickCounter = 0;\n";
			activityContent += "private Button " + activityName+"aButtonSequence;\n";
		}
		
		activityContent += "\n" + mActivityClassTextOnCreateTop.replaceAll("_LAYOUT_NAME_", "R.layout." + activityName.toLowerCase());
		for (int i = 0; i < numSubActivity; i ++)
		{
			String buttonName = activityName+"aButton" + i;
			activityContent += buttonName+" = (Button)this.findViewById(R.id."+buttonName+"Id);\n";
			activityContent += buttonName+"Handler "+activityName+"aButtonListener"+i+" = new "+buttonName+"Handler();\n";
			activityContent += buttonName+".setOnClickListener("+activityName+"aButtonListener"+i+");\n";
		}			
		if (enableConditionsComplex){
			String buttonName = activityName+"aButtonComplex";
			activityContent += buttonName+" = (Button)this.findViewById(R.id."+buttonName+"Id);\n";
			activityContent += buttonName+"Handler "+activityName+"aButtonListenerComplex = new "+buttonName+"Handler();\n";
			activityContent += buttonName+".setOnClickListener("+activityName+"aButtonListenerComplex);\n";			
		}
		if (enableConditionsSequence && numSubActivity > 0){
			String buttonName = activityName+"aButtonSequence";
			activityContent += buttonName+" = (Button)this.findViewById(R.id."+buttonName+"Id);\n";
			activityContent += buttonName+"Handler "+activityName+"aButtonListenerSequence = new "+buttonName+"Handler();\n";
			activityContent += buttonName+".setOnClickListener("+activityName+"aButtonListenerSequence);\n";			
		}
		
		////////////////////////////////////////////////////////////////////////////////////
		//for leaf node/activities only

		//broadcast some intents to the broadcast receivers
		if (numBroadcastToSend > 0)
		{
			numBroadcastToSend--;
			String actionName = receiverBaseName + numBroadcastAdded + "ReceiverAction";
			String broadcastText = "Intent intent = new Intent(\"" + actionName + "\");\n";
			broadcastText += "sendBroadcast(intent);\n";		
			activityContent += broadcastText + "\n";
			numBroadcastAdded++;
		}		
		
		//start some services
		else if (numServiceToStart > 0)
		{
			numServiceToStart--;
			String aServiceName = serviceBaseName + numServiceStarted + "Service";
			String serviceText = "Intent intent = new Intent(this,"+aServiceName+".class);\n";
			serviceText += "startService(intent);\n";		
			activityContent += serviceText + "\n";
			numServiceStarted++;
		}
		
		//access some content providers
		else if (numProviderToAccess > 0)
		{
			numProviderToAccess--;
			String aProviderName = providerBaseName + numProviderAccessed + "Provider";
			String providerText = "super.managedQuery("+aProviderName+".CONTENT_URI, null, null, null, null);\n"; //deprecated method, but ok for our purpose	
			activityContent += providerText + "\n";
			numProviderAccessed++;
		}			

		////////////////////////////////////////////////////////////////////////////////////
		
		activityContent = potentiallyAddTarget(activityContent,true);
		if (numSubActivity <= 0 && enableMethodDepthGen)
		{

			String depthMethodCalls = "";
			for (int j = 0; j < numMethodDepthToGen; j++)
			{
				depthMethodCalls += "private void depthMethod"+j+"(){ ";
				if ( j < numMethodDepthToGen-1)
					depthMethodCalls += "depthMethod"+(j+1)+"();";
				depthMethodCalls += "};\n";
			}

			activityContent = activityContent.replaceAll("_METHOD_DEPTH_TEXT_", depthMethodCalls); 
			activityContent += "depthMethod0();\n";
	
		}		
		activityContent +=  mActivityClassTextOnCreateBottom;
		
		
		for (int i = 0; i < numSubActivity; i ++)
		{			
			int subActivityCountStart = i + nextLevelConnectionNumber;
			String buttonName = activityName+"aButton" + i;
			String listernerText = mActivityClassTextListenerTop.replaceAll("_BUTTON_CLICK_LISTENER_NAME_", buttonName+"Handler");
			
			//subActivityCountStart += i;
			String subActivityName = activityBaseName+subActivityCountStart;
			String onClickBodyText = "Intent myIntent = new Intent("+activityName+".this, "+subActivityName+".class);\n";
			
			//for the conditions
			//first one has 0, then 1 and 2 (nested) and so on	
			if (enableConditions)
			{
				Random r = new Random();
				for (int j = 0; j< i; j++)
				{
					int randomValue = r.nextInt(highConditionValue)+lowConditionValue;
					String inputName = activityName+"anInput"+numConditionsAdded+"Id";
					onClickBodyText += "EditText "+inputName+" = (EditText)findViewById(R.id." + inputName+");\n";
					
					String inputNameDouble = inputName+"Double";
					onClickBodyText += "double "+inputNameDouble+" = 0.0;\n";
					onClickBodyText += "if (" + inputName + " != null && !"+inputName+".getText().toString().equals(\"\")) {\n";				
						onClickBodyText += inputNameDouble+" = Double.parseDouble("+inputName+".getText().toString());\n";
						onClickBodyText += "}\n if (" + inputNameDouble + " > "+randomValue+"){\n";
					numConditionsAdded++;
				}
			}
			
				//condition for sequence counter to be used as well
				if (enableConditionsSequence && useConditionsSequence) 
					onClickBodyText += "if (myButtonClickCounter >=" + minSequenceCount + "){\n";
			
					onClickBodyText += activityName+".this.startActivity(myIntent);\n";	
					onClickBodyText = potentiallyAddTarget(onClickBodyText,true);
				
				if (enableConditionsSequence && useConditionsSequence){
					onClickBodyText += "}\n";
					if (resetConditionSequence){
						onClickBodyText += "myButtonClickCounter=0;\n";
					}
				}
					
			if (enableConditions)
				for (int j = 0; j< i; j++)
					onClickBodyText += "}\n";
			
			
			listernerText = listernerText.replaceAll("_ON_CLICK_BODY_", onClickBodyText);
			
			activityContent +=  listernerText + "\n";
		}

		if (enableConditionsComplex)
		{			
			String buttonName = activityName+"aButtonComplex";
			String listernerText = mActivityClassTextListenerTop.replaceAll("_BUTTON_CLICK_LISTENER_NAME_", buttonName+"Handler");
			String onClickBodyText = "\n";
			
			Random r = new Random();
			for (int k = 0; k< numConditionsToAddComplex; k++)
			{
				int randomValue = r.nextInt(highConditionValue)+lowConditionValue;
				String inputName = activityName+"anInputComplex"+k+"Id";
				onClickBodyText += "EditText "+inputName+" = (EditText)findViewById(R.id." + inputName+");\n";
				
				String inputNameDouble = inputName+"Double";
				onClickBodyText += "double "+inputNameDouble+" = 0.0;\n";
				onClickBodyText += "if (" + inputName + " != null && !"+inputName+".getText().toString().equals(\"\")) {\n";				
					onClickBodyText += inputNameDouble+" = Double.parseDouble("+inputName+".getText().toString());\n";
					onClickBodyText += "}\n if (" + inputNameDouble + " > "+randomValue+"){\n";
			}

			onClickBodyText += "target();\n";		

			for (int k = 0; k< numConditionsToAddComplex; k++)
				onClickBodyText += "}\n";
			
			
			listernerText = listernerText.replaceAll("_ON_CLICK_BODY_", onClickBodyText);
			
			activityContent +=  listernerText + "\n";
		}
		
		if (enableConditionsSequence && numSubActivity > 0)
		{			
			String buttonName = activityName+"aButtonSequence";
			String listernerText = mActivityClassTextListenerTop.replaceAll("_BUTTON_CLICK_LISTENER_NAME_", buttonName+"Handler");
			String onClickBodyText = "\n";
			
			onClickBodyText += "if (myButtonClickCounter >=" + minSequenceCount + "){\n";
				onClickBodyText += "target();\n";	
			onClickBodyText += "} else {\n";
				onClickBodyText += "myButtonClickCounter++;\n";
				onClickBodyText += "}\n";
						
			listernerText = listernerText.replaceAll("_ON_CLICK_BODY_", onClickBodyText);
			
			activityContent +=  listernerText + "\n";
		}
		
		activityContent +=  mActivityClassTextBottom;
		activityContent = activityContent.replaceAll("_TARGET_TEXT_", ""); //if a target wasn't assigned, remove the template text
		activityContent = activityContent.replaceAll("_METHOD_DEPTH_TEXT_", ""); //if method call depth wasn't used, remove the template text
		writeFile(activityFile, activityContent);
	}
	
	private void writeManifestFileShared (String activityName, int numSubActivity)
	{
		////////////////
		DocumentBuilderFactory dbf = null;
		DocumentBuilder db = null;
		Document dom = null;
		Element root = null;

			try
			{
				//deep clone the main activity to set up additional activities
				 dbf = DocumentBuilderFactory.newInstance();
				String manifestFile = appPath + "/AndroidManifest.xml";
				 db = dbf.newDocumentBuilder();
				 dom = db.parse(manifestFile);
				 root = dom.getDocumentElement();
				NodeList applicationList = root.getElementsByTagName("application");
				Element appElement = (Element) applicationList.item(0);
				
				//change name of the main activity
				NodeList nl = root.getElementsByTagName("activity");
				Element mainActivityElement = (Element) nl.item(0);
				
				
				//for (int i = 0; i < numSubActivity; i ++)
				//{
					Element copy = (Element)mainActivityElement.cloneNode(true);
					
					//change activity label and name
					String subActivityName = activityName;//+i;
					copy.setAttribute("android:label", "@string/"+subActivityName);
					copy.setAttribute("android:name", "."+subActivityName);
					
					//change the action type
					NodeList actionList = copy.getElementsByTagName("action");
					Element action = (Element) actionList.item(0);
					action.setAttribute("android:name", "android.intent.action.SEND");
					
					//change the category
					NodeList categoryList = copy.getElementsByTagName("category");
					Element category = (Element) categoryList.item(0);
					category.setAttribute("android:name", "android.intent.category.DEFAULT");
					
					appElement.appendChild(copy);
				//}				
				
				writeXmlFile(dom, manifestFile);
			}catch(Exception e){
				e.printStackTrace();
			}		
	}
	
	private void writeStringsFileShared(String activityName, int numSubActivity)
	{
		DocumentBuilderFactory dbf = null;
		DocumentBuilder db = null;
		Document dom = null;
		Element root = null;
		
		try
		{				
			//update the string values file
			dbf = DocumentBuilderFactory.newInstance();
			String valuesFile = appPathValues + "strings.xml";
			db = dbf.newDocumentBuilder();
			dom = db.parse(valuesFile);
			root = dom.getDocumentElement();	
			
			String subActivityName = activityName;//+i;
			//for the activities
			Element aValue = dom.createElement("string");
			aValue.setAttribute("name", subActivityName);
			aValue.setTextContent(subActivityName);
			//root.appendChild(aValue);
			
			
			String xpath = "//*[@name='"+subActivityName+"']";
			expr = xp.compile(xpath);
			Object result = expr.evaluate(dom, XPathConstants.NODESET);
			NodeList nl2 = (NodeList) result;
			if(nl2 == null || nl2.getLength() <= 0) 
				root.appendChild(aValue);
			
			
			for (int i = 0; i < numSubActivity; i ++)
			{				
				//for the buttons
				String buttonLabel = activityName+"aButton"+i+"Label";
				aValue = dom.createElement("string");
				aValue.setAttribute("name", buttonLabel);
				aValue.setTextContent(buttonLabel);
				
				xpath = "//*[@name='"+buttonLabel+"']";
				expr = xp.compile(xpath);
				result = expr.evaluate(dom, XPathConstants.NODESET);
				nl2 = (NodeList) result;
				if(nl2 == null || nl2.getLength() <= 0) 
					root.appendChild(aValue);
			}
			
			if (enableConditionsComplex)
			{
				//for the buttons
				String buttonLabel = activityName+"aButtonComplexLabel";
				aValue = dom.createElement("string");
				aValue.setAttribute("name", buttonLabel);
				aValue.setTextContent(buttonLabel);
				
				xpath = "//*[@name='"+buttonLabel+"']";
				expr = xp.compile(xpath);
				result = expr.evaluate(dom, XPathConstants.NODESET);
				nl2 = (NodeList) result;
				if(nl2 == null || nl2.getLength() <= 0) 
					root.appendChild(aValue);				
			}
			
			if (enableConditionsSequence)
			{
				//for the buttons
				String buttonLabel = activityName+"aButtonSequenceLabel";
				aValue = dom.createElement("string");
				aValue.setAttribute("name", buttonLabel);
				aValue.setTextContent(buttonLabel);
				
				xpath = "//*[@name='"+buttonLabel+"']";
				expr = xp.compile(xpath);
				result = expr.evaluate(dom, XPathConstants.NODESET);
				nl2 = (NodeList) result;
				if(nl2 == null || nl2.getLength() <= 0) 
					root.appendChild(aValue);				
			}
			
			writeXmlFile(dom, valuesFile);	
		}catch(Exception ex)
		{
			ex.printStackTrace();
		}		
	}	
}
